S3 Selectを使う際は”s3:ListBucket”権限も付与したほうが良いですよ
実装内容
S3 Selectを使った、以下のような構成を実装していました。
- ParquetファイルをS3バケットにアップロード
- S3バケットにはParquetファイル(suffixが
.parquet
)アップロードでトリガされるS3イベント通知を設定。Lambda関数を実行する。 - Lambda関数上でS3イベント通知のイベントペイロードをパースし、アップロードされたファイルに対してS3 Select
- S3 Selectの結果、レコードヒットしたら所定のSlackチャンネルにメッセージポスト
S3 Selectを実行するのに必要な権限は?
S3 Selectを使う際にPrincipal側に必要な権限は、対象バケット内オブジェクトに対する s3:GetObject
のみです。
今回の場合はS3 Selectを実行するのはLambda関数なので、Lambda関数にアタッチするロールに以下のようにs3:GetObject
権限をアタッチしました。
IAMポリシー例
{ "Action": [ "s3:GetObject" ], "Resource": "arn:aws:s3:::(S3バケット名)/*", "Effect": "Allow" }
情報元
以下SelectObjectContentがいわゆるS3 Selectに対応するAPIです。
こちらに以下Permissionについての記載があります。
Permissions
You must have s3:GetObject permission for this operation. Amazon S3 Select does not support anonymous access. For more information about permissions, see Specifying Permissions in a Policy in the Amazon Simple Storage Service Developer Guide.
出くわしたエラー
試しにS3バケットにParquetファイルをアップしてLambda関数を実行したところ、以下のようなエラーが発生します。。
[ERROR] ClientError: An error occurred (AccessDenied) when calling the SelectObjectContent operation: Access Denied (Trace情報が続く)
Access Denied
ですので、以下のようなことを確認しましたが解決できません。
- S3 Selectって
s3:GetObject
以外にも権限必要?→前述のAPIドキュメント等を再確認 - S3バケットポリシーで弾かれている?
- OrganizationsのSCPで弾かれている?(お客様環境だったのでどういう設定になっているか詳しくなかったため)
- ちょうどS3のAccess Deniedエラートラブルシュートのナレッジセンター記事があったのでこれを元に色々調査
解決法
以下のブログエントリに書かれているとおりです。
selectの実行にListBucketは必要ありませんが、指定したオブジェクトが見つからない場合に「An error occurred (NoSuchKey) when calling the SelectObjectContent operation: The specified key does not exist.」を出力するためです。 ListBucketがないと、「An error occurred (AccessDenied) when calling the SelectObjectContent operation: Access Denied」となってしまい切り分けが難しくなります。
IAMポリシー追加
{ "Action": [ "s3:ListBucket" ], "Resource": "arn:aws:s3:::(S3バケット名)", "Effect": "Allow" }
再実行するとエラーメッセージが変わりました。
[ERROR] NoSuchKey: An error occurred (NoSuchKey) when calling the SelectObjectContent operation: The specified key does not exist. (Trace情報が続く)
指定したキーのオブジェクトが無いよ、とのこと。Access Denied
からここにたどり着くのは厳しい。。
なぜThe specified key does not exist
になったのか
本題から逸れますがこの点についても述べておきます。
S3 Selectで使用するS3オブジェクトのキーは、S3イベントのペイロードに記載されているものを使っています。ですのでオブジェクトは存在しているはずです。
なのですが、公式開発者ガイドを見ていて気づきました。オブジェクトキーはURLデコードする必要がありました。
s3 キーは、イベントに関与したバケットとオブジェクトに関する情報を提供します。オブジェクトのキー名の値は URL エンコードされます。たとえば、「red flower.jpg」は「red+flower.jpg」となります
今回の場合、テストしたオブジェクトのキーに「=」が含まれていたため、S3イベント通知のペイロードには「%3D」とURLエンコードされた値が入っていました。それをデコードせずにS3 Selectに突っ込んだためThe specified key does not exist
になっていました。
Lambda関数の修正
Pythonです。 urllib.parse.unquoteを使います。
+ import urllib.parse
def lambda_handler(event, context): logger.debug(event) for r in event['Records']: s3 = r['s3'] bucket = s3['bucket']['name'] + key = urllib.parse.unquote(s3['object']['key']) - key = s3['object']['key'] logger.info("Object path: %s/%s", bucket, key)
まとめ
- S3 Selectを使う際はPrincipalに
s3:GetObject
に加えてs3:ListBucket
も与えておくとデバッグがはかどります。 - S3イベント通知でオブジェクトキーを使う際はURLデコードをお忘れなく。